#include "StdAfx.h"
#include "database_mysql.h"
#include <utility/utility.h>

namespace Zen{

database_mysql::database_mysql(const tstring& url, int port, const tstring& user, const tstring& password, const tstring& dbname, const tstring& charset)
	:url_(url), port_(port), user_(user), password_(password), dbname_(dbname), charset_(charset)/*, &mysql(NULL)*/
{
}


database_mysql::~database_mysql(void)
{
}

bool database_mysql::open()
{
	mysql_init(&mysql_);

#ifdef _UNICODE
	std::string url = utility::ws2s(url_), user = utility::ws2s(user_), 
		password = utility::ws2s(password_), dbname = utility::ws2s(dbname_),
		charset = utility::ws2s(charset_);
#else
	std::string url = url_, user = user_, password = password_, dbname = dbname_, charset = charset_;
#endif
	try
	{

	if (mysql_real_connect(&mysql_, url.c_str(), user.c_str(), password.c_str(), dbname.empty()?NULL:dbname.c_str(), port_, NULL, CLIENT_MULTI_STATEMENTS))
	{
		mysql_set_character_set(&mysql_, charset.c_str());
	}
	else
	{
		mysql_init(&mysql_);
		if (mysql_real_connect(&mysql_, url.c_str(), user.c_str(), password.c_str(), NULL, port_, NULL, CLIENT_MULTI_STATEMENTS))
		{
			if (dbname.empty())
			{
				return true;
			}
			
			std::string sql_create = "create database " + dbname + " character set " + charset;
			if (mysql_real_query(&mysql_, sql_create.c_str(), sql_create.length()))
			{
				error_ = _error_message();
				return false;
			}
			close();
			return open();
		}
		else
		{
			error_ = _error_message();
			return false;
		}
	}
	}
	catch(...)
	{
		error_ = _error_message();
		return false;
	}


	return true;
}

void database_mysql::close()
{
	mysql_close(&mysql_);
}

bool database_mysql::is_open()
{
	return mysql_ping(&mysql_) == 0;
}

bool database_mysql::get_table( const tstring& sql, table_type& table )
{
	int records = 0;
	return get_table(sql, table, records);
}

bool database_mysql::get_table( const tstring& sql, table_type& table, int& records )
{
	records = 0;
	string s = database::_get_coding_sql(sql);

	if(mysql_real_query(&mysql_, s.c_str(), s.length()) == 0)
	{
		MYSQL_RES* res = mysql_store_result(&mysql_);
		if(!res)
		{
			error_ = _error_message();
			return false;
		}

		int column = mysql_num_fields(res);
		MYSQL_ROW row = NULL;
		while(NULL != (row = mysql_fetch_row(res)))
		{
			unsigned long* lengths = mysql_fetch_lengths(res);	//Returns the lengths of the columns of the current row within a result set.

			record_type record;
			for(int i = 0; i < column; i++)
			{
				if (row[i] && lengths[i] > 0)
				{
#if _UNICODE
					string value(row[i], lengths[i]);
					record.push_back(utility::string_to_wstring(value, CP_UTF8));
#else
					record.push_back(row[i]);
#endif
				}
				else
					record.push_back(TEXT(""));
			}
			table.push_back(record);
			row++;
			records++;
		}

		mysql_free_result(res);
	}

	return true;
}

bool database_mysql::execute( const tstring& sql )
{
	string s = database::_get_coding_sql(sql);
	utility::replace_all_distinct(s, "\\", "\\\\");

	if (mysql_real_query(&mysql_, s.c_str(), s.length()))
	{
		error_ = _error_message();
		return false;
	}
	else
	{
		do
		{
			MYSQL_RES* result = mysql_store_result(&mysql_);
			mysql_free_result(result);

		}while(!mysql_next_result(&mysql_)); 
	}

	return true;
}

Zen::tstring database_mysql::_error_message()
{
	const char* err = mysql_error(&mysql_);
	//utility::output_debug_string(err);

#ifdef _UNICODE
	return utility::s2ws(err);
#else
	return err;
#endif
}

bool database_mysql::begin_transaction()
{
	return execute(TEXT("BEGIN"));
}

bool database_mysql::commit_transaction()
{
	return execute(TEXT("COMMIT"));
}

bool database_mysql::exist_table( const tstring& table )
{
	string s = database::_get_coding_sql(table);

	MYSQL_RES* res = mysql_list_tables(&mysql_, s.c_str());
	if (!res)
		return false;

	MYSQL_ROW row = mysql_fetch_row(res);
	if (!row)
		return false;

	mysql_free_result(res);

	return true;
}

bool database_mysql::create_user( const tstring& user, const tstring& password )
{
	tstring sql = utility::StringFormat(1024, TEXT("CREATE USER '%s'@'localhost' IDENTIFIED BY '%s';"), user, password);
	if (!execute(sql))
	{
		return false;
	}

	sql = utility::StringFormat(1024, TEXT("GRANT ALL ON *.* TO '%s'@'localhost';"), user);
	if (!execute(sql))
	{
		return false;
	}

	sql = utility::StringFormat(1024, TEXT("use mysql;UPDATE `user` SET `Grant_priv`='Y' WHERE (`Host`='localhost') AND (`User`='%s');"), user);
	if (!execute(sql))
	{
		return false;
	}

	if (!execute(TEXT("FLUSH PRIVILEGES;")))
	{
		return false;
	}

	return true;
}

bool database_mysql::has_table( const tstring& dbname, const tstring& table )
{
	string s = database::_get_coding_sql(table);

	bool ret = false;
	MYSQL_RES* res = mysql_list_tables(&mysql_, s.c_str());
	do 
	{
		if(!res)
			break;

		MYSQL_ROW row;
		if(!(row = mysql_fetch_row(res)))
			break;

		ret = true;

	} while (0);

	mysql_free_result(res);

	return ret;
}

}
